use crate::utils::db_utils::bson_to_json;
use chrono::{DateTime as CDateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use serde_repr::{Deserialize_repr, Serialize_repr};
use wither::{
    bson::{oid::ObjectId, Bson, DateTime},
    Model,
};

use super::user::SimpleUser;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum ClubLogType {
    Normal = 1,
    Invite = 2,
    Remove = 3,
    RoleChange = 4,
}

/// ## ClubLogModel
/// 社团日志,邀请入社，移除社团成员，权限变更都会产生日志
#[derive(Debug, Clone, Serialize, Deserialize, Model)]
pub struct ClubLogModel {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    #[serde(rename = "type")]
    pub log_type: ClubLogType,
    pub content: Bson,
    pub operator: Option<SimpleUser>,
    pub created_at: DateTime,
}

impl Default for ClubLogModel {
    fn default() -> Self {
        Self {
            id: None,
            log_type: ClubLogType::Normal,
            content: Bson::Null,
            operator: None,
            created_at: DateTime::now(),
        }
    }
}

impl ClubLogModel {
    pub fn new<T: Into<ClubLogType>, C: Into<Bson>, U: Into<Option<SimpleUser>>>(
        log_type: T,
        content: C,
        operator: U,
    ) -> Self {
        Self {
            log_type: log_type.into(),
            content: content.into(),
            operator: operator.into(),
            ..Self::default()
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClubLogModelDTO {
    pub id: Option<String>,
    #[serde(rename = "type")]
    pub log_type: ClubLogType,
    pub content: Value,
    pub operator: Option<SimpleUser>,
    pub created_at: CDateTime<Utc>,
}

impl From<ClubLogModel> for ClubLogModelDTO {
    fn from(model: ClubLogModel) -> Self {
        Self {
            id: model.id.map(|i| i.to_string()),
            log_type: model.log_type,
            content: bson_to_json(&model.content),
            operator: model.operator,
            created_at: model.created_at.to_chrono(),
        }
    }
}
